<template>
  <article class="page page-jssfdat-decrypt">
    <h4 class="text-center">数字教材DAT文件加密解密</h4>
    <form class="form row">
      <div class="col-6">
        <fieldset>
          <legend>加密</legend>
          <div class="fieldset-content">
            <div class="form-group form-item-row" align="center">
              <div class="form-item-input">待加密的JSON文件夹</div>
              <div class="form-item-suffix" title="清空" @click="clearList('encrypt')">
                <i class="fa fa-trash-o"></i>
              </div>
            </div>
            <div class="form-group zip-list" @drop.prevent="encryptDrop" @dragover.prevent >
              <div class="zip-item" v-for="(v,i) in encryptZipsList" :key="v">
                <div class="zip-item-text text-ellipsis" :title="v">{{v}}</div>
                <div v-if="(encryptLoadingCount > 0) && (encryptLoadingCount <= i)" class="zip-item-icon">
                  <x-loading></x-loading>
                </div>
                <div v-else class="zip-item-icon" @click="deleteItem(i, 'encrypt')">
                  <i class="fa fa-close"></i>
                </div>
              </div>
              <div v-show="encryptZipsList.length===0" class="nodata">将待加密的JSON文件夹拖动到此处</div>
            </div>
            <div class="form-group form-item-row" align="center">
              <x-button type="primary" block @click="encrypt" :loading="encryptLoadingCount > 0">执行加密</x-button>
            </div>
          </div>
        </fieldset>
      </div>
      <div class="col-6">
        <fieldset>
          <legend>解密</legend>
          <div class="fieldset-content">
            <div class="form-group form-item-row" align="center">
              <div class="form-item-input">待解密的DAT文件</div>
              <div class="form-item-suffix" title="清空" @click="clearList('decrypt')">
                <i class="fa fa-trash-o"></i>
              </div>
            </div>
            <div class="form-group zip-list" @drop.prevent="decryptDrop" @dragover.prevent >
              <div class="zip-item" v-for="(v,i) in decryptZipsList" :key="v">
                <div class="zip-item-text text-ellipsis" :title="v">{{v}}</div>
                <div v-if="(decryptLoadingCount > 0) && (decryptLoadingCount <= i)" class="zip-item-icon">
                  <x-loading></x-loading>
                </div>
                <div v-else class="zip-item-icon" @click="deleteItem(i, 'decrypt')">
                  <i class="fa fa-close"></i>
                </div>
              </div>
              <div v-show="decryptZipsList.length===0" class="nodata">将待解密的DAT文件拖动到此处</div>
            </div>
            <div class="form-group form-item-row" align="center">
              <x-button type="primary" block @click="decrypt" :loading="decryptLoadingCount > 0">执行解密</x-button>
            </div>
          </div>
        </fieldset>
      </div>
    </form>
  </article>
</template>

<script>
const fs = global.require('fs')
const path = global.require('path')
// let aesjs = require('aes-js') // 该库功能在cyberplayer_aes中有包含，故不单独加载
let JSZip = global.JSZip || null
let KEY256 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
// let aesCtr = new cyberplayer_aes.default.ModeOfOperation.ctr(KEY256)

export default {
  name: 'jssfdat-decrypt',
  data () {
    return {
      encryptToPath: this.$sharedObject('desktopPath'),
      encryptPassword: KEY256,
      encryptZipsList: [],
      encryptLoadingCount: 0,
      decryptToPath: this.$sharedObject('desktopPath'),
      decryptPassword: KEY256,
      decryptZipsList: [],
      decryptLoadingCount: 0
    }
  },
  methods: {
    // 拖拽添加待加密文件
    encryptDrop (e) {
      const fileList = e.dataTransfer.files
      if (!fileList) return
      for (let i = 0; i < fileList.length; i++) {
        const file = fileList[i]
        let fileStat = fs.statSync(file.path)
        if (fileStat.isFile()) {
          return this.$toast('请选择文件夹！')
        }
        this.encryptZipsList.push(file.path)
      }
    },
    // 拖拽添加待解密文件
    decryptDrop (e) {
      const fileList = e.dataTransfer.files
      if (!fileList) return
      for (let i = 0; i < fileList.length; i++) {
        const file = fileList[i]
        let fileStat = fs.statSync(file.path)
        if (fileStat.isDirectory()) {
          return this.$toast('请选择待解密的DAT文件！')
        }
        this.decryptZipsList.push(file.path)
      }
    },
    // 删除条目
    deleteItem (index, type) {
      if (type === 'encrypt') {
        this.encryptZipsList.splice(index, 1)
      } else if (type === 'decrypt') {
        this.decryptZipsList.splice(index, 1)
      }
    },
    clearList (type) {
      if (type === 'encrypt') {
        this.encryptZipsList = []
        this.encryptLoadingCount = 0
      } else if (type === 'decrypt') {
        this.decryptZipsList = []
        this.decryptLoadingCount = 0
      }
    },
    // 加密
    encrypt () {
      this.encryptLoadingCount = 0
      this.encryptRecursion({
        index: 0,
        length: this.encryptZipsList.length
      })
    },
    // 加密·递归
    encryptRecursion (options) {
      options = options || {}
      let from = this.encryptZipsList[options.index] || ''
      this.encryptLoadingCount++
      this.$nextTick(() => {
        let zip = new JSZip()
        fs.readdirSync(from).forEach((fileName) => {
          let filePath = path.join(from, fileName)
          let fileContent = fs.readFileSync(filePath)
          zip.file(fileName, fileContent.toString())
        })
        zip.generateAsync({
          type: 'nodebuffer',
          compression: 'DEFLATE'
        }).then((content) => {
          let aesCtr = new cyberplayer_aes.default.ModeOfOperation.ctr(KEY256)
          let encryptedBytes = aesCtr.encrypt(content)
          let toPath = `${from}.dat`
          fs.writeFile(toPath, encryptedBytes, (err) => {
            if (err) {
              console.error('Error happend when write AES file', err)
            }
            if (options.index < (options.length - 1)) {
              this.encryptRecursion({
                index: options.index + 1,
                length: options.length
              })
            } else {
              this.encryptLoadingCount = 0
            }
          })
        })
      })
    },
    // 解密
    decrypt () {
      this.decryptLoadingCount = 0
      this.decryptRecursion({
        index: 0,
        length: this.decryptZipsList.length,
      })
    },
    // 解密·递归
    decryptRecursion (options) {
      options = options || {}
      let from = this.decryptZipsList[options.index] || ''
      if (!from) return
      this.decryptLoadingCount++
      this.$nextTick(() => {
        let aesCtr = new cyberplayer_aes.default.ModeOfOperation.ctr(KEY256)
        let content = fs.readFileSync(from)
        let decryptedBytes = aesCtr.decrypt(content)
        let toDirroot = path.dirname(from)
        let toDirname = path.basename(from).split('.')[0]
        toDirroot = path.join(toDirroot, toDirname)
        let zip = new JSZip()
        console.log('from:', from)
        console.log('decryptedBytes:', decryptedBytes)
        zip.loadAsync(decryptedBytes).then(() => {
          zip.forEach((relativePath, file) => {
            file.async('string').then((content) => {
              let toFilename = path.join(toDirroot, relativePath)
              this.$sharedObject('jstoolsNode').writeFileSync(toFilename, content)
            })
          })
          if (options.index < (options.length - 1)) {
            this.decryptRecursion({
              index: options.index + 1,
              length: options.length
            })
          } else {
            this.decryptLoadingCount = 0
          }
        })
      })
    }
  }
}
</script>

<style scoped lang="less">
@import "~@/assets/css/_mixins.less";
@import "~@/assets/css/_color.less";
.form-item-row {
  display: flex;
  .form-item-label {
    min-width: 4em;
    margin-right: .5em;
    text-align-last: justify;
  }
  .form-item-input {
    width: 0;
    flex-grow: 1;
    text-align: left;
  }
  .form-item-suffix {
    margin-left: .5em;
    min-width: 2em;
  }
  &[align="center"] {
    align-items: center;
  }
}
.page-jssfdat-decrypt {
  display: flex;
  flex-direction: column;
  .form {
    flex-grow: 1;
    fieldset {
      height: 100%;
      .fieldset-content {
        height: calc(100% - 2em);
        display: flex;
        flex-direction: column;
        .zip-list {
          height: 0;
          flex-grow: 1;
          padding: .5em;
          border-radius: .5em;
          background-color: #fff;
          box-shadow: 0 0 .5em @bgGrey;
          overflow: hidden auto;
          position: relative;
          .zip-item {
            height: 2em;
            display: flex;
            align-items: center;
            .zip-item-text {
              width: 0;
              flex-grow: 1;
            }
            .zip-item-icon {
              padding: 0 .5em;
              cursor: pointer;
            }
          }
        }
      }
    }
  }
}
</style>
